<?php


namespace App\Tools;

use GuzzleHttp\Client;
use Illuminate\Support\Facades\Cache;
use Ramsey\Uuid\Uuid;
use Godruoyi\Snowflake\Snowflake;

class Common
{

    /**
     * 对url进行urlencode
     */
    public static function urlencode($url)
    {
        $path = parse_url($url, PHP_URL_PATH);

        $encoded_path = array_map('urlencode', explode('/', $path));

        return str_replace($path, implode('/', $encoded_path), $url);
    }

    /**
     * 发起请求
     * @param array $data
     * @return string
     */
    public static function request($url, $data, $method = 'POST')
    {

        $client = new Client([
            'timeout' => 10,
            'headers' => [
                'Content-Type' => 'application/json'
            ],
        ]);

        $response = $client->request($method, $url, [
            'json' => $data
        ]);

        $res_string =  $response->getBody()->getContents();

        return json_decode($res_string, true);
    }

    /**
     * 获取一天的开始时间
     * @param string $user
     * @param string $pwd
     * @param integer $position
     * @return string
     */
    public static function getStartTime($time)
    {

        return strtotime(date("Y-m-d", $time)); //当天开始时间时间戳;
    }

    /**
     * 无限分类
     *
     * @param   array $arr 待分类的数据
     * @param   int /string $id 要找的子节点父级id
     * @param   int $level 节点等级
     * @param   string $p_id 父级id字段
     * @return array  数组
     */
    public static function getTree($arr, $id = 0, $lev = 0, $p_id = 'p_id')
    {
        // // 获取子孙树
        // if (empty($arr)) {
        //     return false;
        // }
        $tree = [];
        foreach ($arr as $v) {
            if ($v[$p_id] == $id) {
                $v['level'] = $lev;
                $v['itemList'] = self::getTree($arr, $v['guid'], $lev + 1);
                $tree[] = $v;
            }
        }
        return $tree;
    }

    /**
     * 获取树形结构
     * @param array $list
     * @param string $p_key
     * @param string $key
     * @param  $pid
     * @return array
     */
    public static function treeList(array $list, string $p_key = 'pid', string $key = 'id', $pid = 0): array
    {
        $res = [];
        foreach ($list as $one) {
            if ($one[$p_key] == $pid) {
                $one['children'] = self::treeList($list, $p_key, $key, $one[$key]);
                if (empty($one['children'])) {
                    unset($one['children']);
                }
                $res[] = $one;
            }
        }

        return $res;
    }

    /**
     * 雪花算法 生成唯一整数序列
     * @param string $user
     * @param string $pwd
     * @param integer $position
     * @return string
     */
    public static function getIntid()
    {

        return (new Snowflake())
            ->setStartTimeStamp(strtotime('2022-01-01') * 1000)
            ->setSequenceResolver(function ($currentTime) {

                if (Cache::add($currentTime, 1, 1)) {
                    return 0;
                }

                return Cache::increment($currentTime, 1);
            })->id();
    }

    /**
     * 加密算法
     * @param string $user
     * @param string $pwd
     * @param integer $position
     * @return string
     */
    public static function cryptString($user, $pwd, $position = 2)
    {
        $offset = 'Exam';
        $subUser = substr(md5($user), 0, $position);
        $cryptPwd = md5($pwd);
        return md5(md5($cryptPwd . $subUser) . $offset);
    }

    /**
     * 生成随机串
     * @param  int 生成长度
     * @return string 生成的字条串
     */
    public static function random($length)
    {
        $hash = '';
        $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
        $max = strlen($chars) - 1;
        PHP_VERSION < '4.2.0' && mt_srand((float) microtime() * 1000000);
        for ($i = 0; $i < $length; $i++) {
            $hash .= $chars[mt_rand(0, $max)];
        }
        return $hash;
    }

    public static function getUuid()
    {
        return Uuid::uuid4()->getHex()->toString();
    }

    /**
     * 循环对参数每个值进行去空格处理
     *
     * @param $param
     * @return array
     */
    public static function trimParam($param)
    {
        // 返回值
        $where = [];
        // 检查参数
        if (!is_array($param['where'])) {
            return $where;
        }
        // 循环对参数每个值进行去空格处理
        foreach ($param['where'] as $key => $value) {
            if (!empty($value) && !is_array($value)) {
                if (!empty(trim($value))) {
                    $where[$key] = trim($value);
                }
            }
            if (is_array($value) && count($value) > 0) {
                $where[$key] = $value;
            }
        }

        return $where;
    }

    /**
     * 循环对参数每个值进行去空格处理
     *
     * @param $param
     * @return array
     */
    public static function trimData($param)
    {
        $data = [];

        // 循环对参数每个值进行去空格处理
        foreach ($param as $key => $value) {
            if (!empty($value) && !is_array($value)) {
                if (!empty(trim($value))) {
                    $data[$key] = trim($value);
                }
            }
            if (is_array($value) && count($value) > 0) {
                $data[$key] = $value;
            }
        }

        return $data;
    }

    /**
     * CURLf方法
     * @param $url
     * @param bool $data
     * @param int $ispost
     * @param int $https
     * @return bool|mixed
     */
    public static function Curl($url, $data = false, $ispost = 1, $https = 0)
    {
        $httpInfo = array();
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36');
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        if ($https) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // 对认证证书来源的检查
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); // 从证书中检查SSL加密算法是否存在
        }
        if ($ispost) {
            //            $headers[] = 'Content-Type: application/json;charset=utf-8';
            //            $headers[] = 'Content-Length:' . strlen($data);
            //            // 设置header头
            //            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            curl_setopt($ch, CURLOPT_URL, $url);
        } else {
            if ($data) {
                if (is_array($data)) {
                    $data = http_build_query($data);
                }
                curl_setopt($ch, CURLOPT_URL, $url . '?' . $data);
            } else {
                curl_setopt($ch, CURLOPT_URL, $url);
            }
        }

        $response = curl_exec($ch);

        if ($response === FALSE) {
            return false;
        }

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $httpInfo = array_merge($httpInfo, curl_getinfo($ch));

        curl_close($ch);

        return $response;
    }


    /**
     * 根据起点坐标和终点坐标测距离
     * @param  [array]   $from 	[起点坐标(经纬度),例如:array(118.012951,36.810024)]
     * @param  [array]   $to 	[终点坐标(经纬度)]
     * @param  [bool]    $km        是否以公里为单位 false:米 true:公里(千米)
     * @param  [int]     $decimal   精度 保留小数位数
     * @return [string]  距离数值
     */
    public static function get_distance($from, $to, $km = true, $decimal = 2)
    {
        sort($from);
        sort($to);
        $EARTH_RADIUS = 6370.996; // 地球半径系数

        $distance = $EARTH_RADIUS * 2 * asin(sqrt(pow(sin(($from[0] * pi() / 180 - $to[0] * pi() / 180) / 2), 2) + cos($from[0] * pi() / 180) * cos($to[0] * pi() / 180) * pow(sin(($from[1] * pi() / 180 - $to[1] * pi() / 180) / 2), 2))) * 1000;

        if ($km) {
            $distance = $distance / 1000;
        }

        return round($distance, $decimal);
    }

    /**
     * 导出csv
     * params $filename 文件名称 必传
     * params $headerList 头部列表信息(一维数组) 必传
     * params $data 导出的数据(二维数组)  必传
     * @author gl
     */
    public static function export_to_csv($fileName = '', $headArr = [], $data = [])
    {

        ini_set('memory_limit', '1024M'); // 设置程序运行的内存         
        ini_set('max_execution_time', 0); // 设置程序的执行时间,0为无上限 

        ob_end_clean();  // 清除内存
        ob_start();

        //设置header头
        header("Content-Type: text/csv");
        // header("Content-Disposition:filename=" . $fileName . '.csv'); // 不设 attachment 属性 QQ浏览器可预览
        header('Content-Disposition: attachment;filename=' . $fileName . '.csv'); // attachment 属性qq浏览器可修改下载文件名

        //打开PHP文件句柄,php://output,表示直接输出到浏览器
        $fp = fopen('php://output', 'w');

        //使用fputcsv将数据写入文件句柄
        fwrite($fp, chr(0xEF) . chr(0xBB) . chr(0xBF));
        fputcsv($fp, $headArr);

        $index = 0;

        foreach ($data as $item) {

            if ($index == 1000) { // 每次写入1000条数据清除内存   

                $index = 0;

                //刷新一下输出buffer，防止由于数据过多造成问题    
                ob_flush(); // 清除内存                 
                flush();
            }

            $index++;
            if (is_object($item)) {

                fputcsv($fp, (array)$item);
            } else {

                fputcsv($fp, $item);
            }
        }

        ob_flush();
        flush();
        ob_end_clean();
        exit();
    }
}
